#include    "os.h"

#include    <cstdio>
#include    <string>
#include    <vector>

#include	<fcntl.h>
#include	<sys/stat.h>

#if defined(_WIN32)
#	include	<Windows.h>
#	include	<io.h>
#	include	<direct.h>
#else
#	include	<unistd.h>
#endif

bool Exists(const char * path) {
    if (!path || !path[0]) return false;

#if defined(_WIN32)
	return _access(path, 0) == 0;
#else
	return access(path, 0) == 0;
#endif
}

bool MakeDir(const char * path) {
    if (!path || !path[0]) return false;

    std::vector<std::string> folders;
    std::string name, dir(path);
    name.reserve(512);

    for (size_t i = 0; i < dir.size(); ++i) {
        if (dir[i] == '\\' || dir[i] == '/') {
            if (name.back() != '/') {
                folders.push_back(name);
                name.push_back('/');
            }
        } else {
            name.push_back(dir[i]);
        }
    }

    folders.push_back(name);

    for (auto & folder : folders) {
#if defined(_WIN32)
        if (_access(folder.c_str(), 0) != 0) {
            if (_mkdir(folder.c_str()) != 0)
                return false;
        }
#else
        if (access(folder.c_str(), 0) != 0) {
            if (mkdir(folder.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) != 0)
                return false;
        }
#endif
    }

    return true;
}

bool Copy(const char * path, const char * to) {
    if (!Exists(path)) return false;

    FILE * reader = fopen(path, "rb");
    FILE * writer = fopen(to, "wb+");
    
    if (!reader || !writer) return false;

    char buf[1024] = {0};

    do {
        size_t readed = fread(buf, 1, 1024, reader);
        if (readed > 0) fwrite(buf, 1, readed, writer);
    } while (!feof(reader));
    
    fflush(writer);
    fclose(writer);
    fclose(reader);

    return true;
}

bool Delete(const char * path) {
    if (!path || !path[0]) return false;
    return remove(path) == 0;
}

size_t FileSize(const char * path) {
    if (!Exists(path)) return 0;

    int fd = -1;
    struct stat info;

    if ((fd = open(path, O_RDONLY)) == -1 || 0 != fstat(fd, &info) || !(info.st_mode & S_IFREG)) {
        if (fd >= 0) close(fd);
        return 0;
    }

    close(fd);
    return (size_t)info.st_size;
}
